using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using OpenFlashChartLib.Charts;
using OpenFlashChartLib.Json;
using ChartBase=OpenFlashChartLib.Charts.ChartBase;
using XAxis=OpenFlashChartLib.Charts.XAxis;
using YAxis=OpenFlashChartLib.Charts.YAxis;

namespace OpenFlashChartLib
{
    public class Graph
    {
        private IList<ChartBase> elements;
        private XAxis x_axis;
        private YAxis y_axis;

        public Graph()
        {
            Elements = new List<ChartBase>();
            Y_Axis_Right = new YAxis();
            Y_Legend = new Legend();
            X_Legend = new Legend();
            Tooltip = new ToolTip(null);
        }

        [JsonProperty("title")]
        public Title Title { set; get; }

        [JsonProperty("x_axis")]
        public XAxis X_Axis
        {
            get
            {
                if (x_axis == null)
                    x_axis = new XAxis();
                return x_axis;
            }
            set { x_axis = value; }
        }

        public bool X_AxisSpecified
        {
            get
            {
                if (elements == null || elements.Count == 0)
                    return false;
                return elements[0].X_AxisSpecified;
            }
        }

        [JsonProperty("y_axis")]
        public YAxis Y_Axis
        {
            get
            {
                if (y_axis == null)
                    y_axis = new YAxis();
                return y_axis;
            }
            set { y_axis = value; }
        }

        public bool Y_AxisSpecified
        {
            get
            {
                if (elements == null || elements.Count == 0)
                    return false;
                return elements[0].Y_AxisSpecified;
            }
        }

        [JsonProperty("elements")]
        public IList<ChartBase> Elements
        {
            get { return elements; }
            set { elements = value; }
        }

        [JsonProperty("y_axis_right")]
        public YAxis Y_Axis_Right { get; set; }

        public bool Y_Axis_RightSpecified
        {
            get { return Y_Axis_Right.IsSpecified(); }
        }

        [JsonProperty("x_legend")]
        public Legend X_Legend { get; set; }

        public bool X_LegendSpecified
        {
            get { return X_Legend.IsSpecified(); }
        }

        [JsonProperty("y_legend")]
        public Legend Y_Legend { get; set; }

        public bool Y_LegendSpecified
        {
            get { return Y_Legend.IsSpecified(); }
        }

        [JsonProperty("bg_colour")]
        public string Bgcolor { get; set; }

        [JsonProperty("tooltip")]
        public ToolTip Tooltip { get; set; }

        public bool TooltipSpecified
        {
            get { return Tooltip.IsSpecified(); }
        }

        public void AddElement(ChartBase chart)
        {
            if (elements.Count == 1)
                throw new ArgumentOutOfRangeException("The number of charts should be 0 or 1");
            elements.Add(chart);
        }

        public override string ToString()
        {
            OnBuildComplete();
            var sw = new StringWriter(CultureInfo.InvariantCulture);
            using (var writer = new JsonWriter(sw))
            {
                writer.UseXmlSerializationAttributes = true;
                writer.SkipNullValue = true;
                writer.Write(this);
            }
            return sw.ToString();
        }

        public string ToPrettyString()
        {
            var sw = new StringWriter(CultureInfo.InvariantCulture);
            using (var writer = new JsonWriter(sw))
            {
                writer.UseXmlSerializationAttributes = true;
                writer.SkipNullValue = true;
                writer.PrettyPrint = true;
                writer.Write(this);
            }
            return sw.ToString();
        }

        public virtual void OnBuildComplete()
        {
            BuildLabels();
            if (!Y_Axis.Max.HasValue)
            {
                BuildMaxValue();
            }
        }

        public void BuildMaxValue()
        {
            foreach (var chart in elements)
            {
                var max = Math.Ceiling(chart.GetMaxValue());
                if (max > (Y_Axis.Max ?? -1))
                {
                    Y_Axis.Max = max;
                }
            }
        }

        public void BuildLabels()
        {
            foreach (var chart in elements)
            {
                chart.BuildLabels(X_Axis, Y_Axis);
            }
        }
    }
}